package net.jcip.examples.chapter14;

import net.jcip.annotations.*;

/**
 * BoundedBuffer
 * <p/>
 * Bounded buffer using condition queues
 * @author Brian Goetz and Tim Peierls
 *
 *
 *
 * notifyAll() vs notify()
 * 	•	notifyAll() 会唤醒所有在该对象上等待的线程。
 * 	•	notify() 只会唤醒一个在该对象上等待的线程。
 *
 * 在某些情况下，使用 notifyAll() 可以避免潜在的死锁情况，因为它确保所有等待的线程都有机会被唤醒，重新竞争锁。
 * 特别是在生产者-消费者模式中，使用 notifyAll() 可以确保无论是生产者还是消费者，都有机会被唤醒继续执行。
 */
@ThreadSafe
public class BoundedBuffer <V> extends BaseBoundedBuffer<V> {
    // CONDITION PREDICATE: not-full (!isFull())
    // CONDITION PREDICATE: not-empty (!isEmpty())
    public BoundedBuffer() {
        this(100);
    }

    public BoundedBuffer(int size) {
        super(size);
    }

    // BLOCKS-UNTIL: not-full
    public synchronized void put(V v) throws InterruptedException {
        while (isFull())
            //如果队列已满  此时生产者进入休眠状态  只有当消费者消费元素之后，消费者调用notifyAll() 唤醒休眠的生产者
            wait();
        doPut(v);
        //当一个线程持有一个对象的监视器锁（通过 synchronized 块或方法获得）时，它可以调用 notifyAll() 方法唤醒所有在该对象上等待的线程。
        // 这些被唤醒的线程将尝试重新获得对象的监视器锁，以继续执行。
        notifyAll();
    }

    // BLOCKS-UNTIL: not-empty
    public synchronized V take() throws InterruptedException {
        while (isEmpty())
            wait();
        V v = doTake();
        notifyAll();
        return v;
    }

    // BLOCKS-UNTIL: not-full
    // Alternate form of put() using conditional notification
    public synchronized void alternatePut(V v) throws InterruptedException {
        while (isFull())
            wait();
        boolean wasEmpty = isEmpty();
        doPut(v);
        if (wasEmpty)
            notifyAll();
    }
}
